home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include "emu.h"
- #include "const.h"
-
- int modrm;
-
- char saw[256*8];
-
- int status_word = 0;
- int control_word = 0x77e;
- reg regs[8] = {
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- { SIGN_POS, TW_E, 0, 0x0, 0x0 },
- };
- int top = 0;
-
- FUNC esc_table[64] = {
- emu_00, emu_10, emu_20, emu_30, emu_40, emu_50, emu_60, emu_70,
- emu_01, emu_11, emu_21, emu_31, emu_41, emu_51, emu_61, emu_71,
- emu_02, emu_12, emu_22, emu_32, emu_42, emu_52, emu_62, emu_72,
- emu_03, emu_13, emu_23, emu_33, emu_43, emu_53, emu_63, emu_73,
- emu_04, emu_14, emu_24, emu_34, emu_44, emu_54, emu_64, emu_74,
- emu_05, emu_15, emu_25, emu_35, emu_45, emu_55, emu_65, emu_75,
- emu_06, emu_16, emu_26, emu_36, emu_46, emu_56, emu_66, emu_76,
- emu_07, emu_17, emu_27, emu_37, emu_47, emu_57, emu_67, emu_77,
- };
-
- int emu_initted = 0;
-
- void emu_entry()
- {
- if (emu_initted != 0x12345678)
- {
- emu_initted = 0x12345678;
- // eprintf(
- // "Installing the 80387 Emulator. Copyright (C) 1991 DJ Delorie.\n"
- // "WARNING: This is a TEST version of this emulator. If it doesn't work,\n"
- // "then don't use it. Not all of the opcodes are implemented, and the\n"
- // "ones that are may not work right in extreme cases. Use at your own risk.\n"
- // );
- }
- // eprintf("eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x\n", eax, ebx, ecx, edx);
- // eprintf("esi=0x%08x edi=0x%08x ebp=0x%08x eip=0x%08x\n", esi, edi, ebp, eip);
- if (*eip == 0x66) // operand size - we know what size we need
- eip++;
- if (*eip == 0x9b) // fwait
- return;
- // int see = ((int)(eip[0] & 7) << 8) | eip[1];
- // if (saw[see] != 42)
- // {
- // eprintf("EMU387: %02x %02x %02x %02x - e%d%d", eip[0], eip[1], eip[2], eip[3], eip[0]&7, (eip[1]>>3)&7);
- // eprintf(" s%d\n", eip[1]&7);
- // saw[see] = 42;
- // }
- int esc_value = *eip++ & 7;
- modrm = *eip++;
- esc_value |= (modrm & 070);
- (esc_table[esc_value])();
- // emu_printall();
- }
-
- void emu_bad()
- {
- eprintf("Unimplemented 80387 Opcode at eip=0x%08x : %02x", eip-2, eip[-2]);
- if (eip[-1] > 0277)
- eprintf(" %02x", eip[-1]);
- else
- eprintf(" /%d", (eip[-1]>>3)&7);
- eprintf(" - e%d%d", eip[-2]&7, (eip[-1]>>3)&7);
- if (eip[-1] > 0277)
- eprintf(" s%d", eip[-1]&7);
- eprintf("\n");
- exception(EX_I);
- }
-
- void emu_printall()
- {
- static char *tag_desc[] = { "Valid", "Zero", "Special", "Empty" };
- status_word = status_word & ~SW_TOP;
- status_word += (top&7) * SW_TOPS;
- eprintf(" SW: 0x%04x top=%d cc=%d%d%d%d ", status_word, top&7,
- status_word & SW_C3?1:0, status_word & SW_C2?1:0,
- status_word & SW_C1?1:0, status_word & SW_C0?1:0);
- eprintf("CW: 0x%04x\n", control_word);
- for (int i=0; i<8; i++)
- {
- reg *r = &st(i);
- switch (r->tag)
- {
- case TW_E:
- continue;
- eprintf("st(%d) ", i);
- break;
- case TW_Z:
- eprintf("st(%d) %c .0000 0000 0000 0000 ",
- i, r->sign ? '-' : '+');
- break;
- case TW_S:
- case TW_V:
- eprintf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
- r->sign ? '-' : '+',
- (long)(r->sigh >> 16),
- (long)(r->sigh & 0xFFFF),
- (long)(r->sigl >> 16),
- (long)(r->sigl & 0xFFFF),
- r->exp - EXP_BIAS + 1);
- }
- eprintf("%s\n", tag_desc[r->tag]);
- }
- fflush(stderr);
- }
-
- static struct {
- int type;
- char *name;
- } ex_names[] = {
- EX_SO, "stack overflow",
- EX_SU, "stack underflow",
- EX_P, "loss of precision",
- EX_U, "underflow",
- EX_O, "overflow",
- EX_Z, "divide by zero",
- EX_D, "denormalized operand",
- EX_I, "invalid operation",
- 0,0
- };
-
- void exception(int n)
- {
- int i;
- status_word |= n;
- if (n == EX_SU)
- status_word &= ~SW_C1;
- for (i=0; ex_names[i].type; i++)
- if (ex_names[i].type == n)
- break;
- if (ex_names[i].type)
- eprintf("80387 Exception: %s!\n", ex_names[i].name);
- else
- eprintf("80387 Exception: 0x%04x!\n", n);
- if (~control_word & n & CW_EXM)
- {
- emu_printall();
- asm("movl $0x4cff,%eax");
- asm("int $0x21");
- }
- }
-
- void setcc(int cc)
- {
- status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3);
- status_word |= cc & (SW_C0|SW_C1|SW_C2|SW_C3);
- }
-
- int full()
- {
- if (st(7).tag != TW_E)
- {
- exception(EX_SO);
- top--;
- r_mov(CONST_NAN, st(0));
- return 1;
- }
- return 0;
- }
-
- int empty(int i)
- {
- if (st(i).tag == TW_E)
- {
- exception(EX_SU);
- return 1;
- }
- return 0;
- }
-
- static int sregval(int reg, int mod)
- {
- switch (reg)
- {
- case 0: return eax;
- case 1: return ecx;
- case 2: return edx;
- case 3: return ebx;
- case 4: return (mod==-1) ? 0 : esp;
- case 5: return mod ? ebp : 0; // data
- case 6: return esi;
- case 7: return edi;
- }
- }
-
- static int scale[] = { 1, 2, 4, 8 };
-
- static int getsib()
- {
- int mod = modrm >> 6;
- int sib = *eip++;
- int ss = sib>>6;
- int index = (sib>>3) & 7;
- int base = sib & 7;
- int rv = sregval(base, mod) + sregval(index, -1) * scale[ss];
- int rv2;
- switch (mod)
- {
- case 1:
- rv2 = *(signed char *)eip++;
- rv += rv2;
- break;
- case 0:
- if (base != 5)
- break;
- case 2:
- ((unsigned char *)&rv2)[0] = *eip++;
- ((unsigned char *)&rv2)[1] = *eip++;
- ((unsigned char *)&rv2)[2] = *eip++;
- ((unsigned char *)&rv2)[3] = *eip++;
- rv += rv2;
- break;
- }
- return rv;
- }
-
- static int regval(int reg, int mod)
- {
- switch (reg)
- {
- case 0: return eax;
- case 1: return ecx;
- case 2: return edx;
- case 3: return ebx;
- case 4: return getsib();
- case 5: return mod ? ebp : 0; // data
- case 6: return esi;
- case 7: return edi;
- }
- }
-
- void *get_modrm()
- {
- int mod = modrm>>6;
- int rm = modrm & 7;
- int rv;
- switch (mod)
- {
- case 0:
- if (rm == 5)
- {
- ((unsigned char *)&rv)[0] = *eip++;
- ((unsigned char *)&rv)[1] = *eip++;
- ((unsigned char *)&rv)[2] = *eip++;
- ((unsigned char *)&rv)[3] = *eip++;
- }
- else
- rv = regval(rm, mod);
- break;
- case 1:
- if (rm != 4)
- rv = (*(signed char *)eip++) + regval(rm, mod);
- else
- rv = regval(rm, mod);
- break;
- case 2:
- if (rm != 4)
- {
- ((unsigned char *)&rv)[0] = *eip++;
- ((unsigned char *)&rv)[1] = *eip++;
- ((unsigned char *)&rv)[2] = *eip++;
- ((unsigned char *)&rv)[3] = *eip++;
- rv += regval(rm, mod);
- }
- else
- rv = regval(rm, mod);
- break;
- case 3:
- eprintf("Attempt to get address from mod = 3\n");
- exit(1);
- }
- // eprintf("modrm returning 0x%x\n", rv);
- return (void *)rv;
- }
-